﻿using Microsoft.SqlServer.Server;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UFIDA.U9.ISV.Item;
using UFSoft.UBF.Business;

namespace ufida.u9.ait.openapi.utils
{
    class DTOUtils
    {
        static bool IsValid = true;

        static DTOUtils()
        {
            IsValid = U9Utils.IsValid();
        }
        /// <summary>
        /// 通过传入参数获取实体单号
        /// 支持传入 DocNo,Code
        /// 支持DescFlexField处理
        /// 支持参考料号Code1/Code2
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static string GetDocNo(object dto)
        {

            //获取单号 DocNo/Code
            //docno中记录实际编码字段
            string docno = "";
            if (ReflexUtils.GetValue("DocNo", dto) != "")
            {
                docno = ReflexUtils.GetValue("DocNo", dto);
            }
            else if (ReflexUtils.GetValue("Code", dto) != "")
            {
                docno = ReflexUtils.GetValue("Code", dto);
            }
            if (string.IsNullOrEmpty(docno))
                throw new Exception($"dto中不存在字段[DocNo/Code],或值为空");

            if (docno.StartsWith("PubDescSeg") || docno.StartsWith("PrivateDescSeg"))
            {
                //从扩展字段中获取单号
                object descObj = ReflexUtils.GetObjectValue("DescFlexField", dto);
                if (descObj == null)
                    descObj = ReflexUtils.GetObjectValue("DescFlexSegments", dto);
                if (descObj == null)
                    throw new Exception($"dto中不存在字段[DescFlexField/DescFlexSegments],或值为空");
                if (!(descObj is CopyOfDescFlexSegmentsData))
                    throw new Exception("扩展字段类型不为[CopyOfDescFlexSegmentsData]");
                docno = ReflexUtils.GetValue(docno, descObj);
            }else if (docno == "Code1" || docno == "Code2")
            {
                //料品参考料号
                docno = ReflexUtils.GetValue(docno, dto);
            }

            if (string.IsNullOrEmpty(docno))
                throw new Exception("获取单号为空");

            return docno;
        }
        /// <summary>
        /// 通过传入参数获取实体查询Path
        /// 支持传入 DocNo,Code
        /// 支持DescFlexField处理
        /// </summary>
        /// <param name="dto">DTO传入对象</param>
        /// <param name="codefield">指定code字段,如果未指定,按照DTO包含字段处理</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static string GetDocNoPath(object dto,string codefield=null)
        {
            //获取真实单号
            string realno=GetDocNo(dto);
            //获取字段[DocNo/Code]值
            //docno中记录实际编码字段
            string docno = "";
            if (ReflexUtils.GetValue("DocNo", dto) != "")
            {
                docno = ReflexUtils.GetValue("DocNo", dto);
                if(string.IsNullOrEmpty(codefield))
                    codefield = "DocNo";
            }
            else if(ReflexUtils.GetValue("Code", dto) != "")
            {
                docno = ReflexUtils.GetValue("Code", dto);
                if (string.IsNullOrEmpty(codefield))
                    codefield = "Code";
            }

            //依据单号字段,构造path
            string path="";
            if (docno.StartsWith("PubDescSeg") || docno.StartsWith("PrivateDescSeg"))
            {
                //扩展字段
                if (ReflexUtils.HasField("DescFlexField", dto))
                {
                    path = $"DescFlexField.{docno}='{realno}'";
                }
                else if (ReflexUtils.HasField("DescFlexSegments", dto))
                {
                    path = $"DescFlexSegments.{docno}='{realno}'";
                }
            }
            else if (docno == "Code1"||docno=="Code2")
            {
                //参考料号1/2
                path = $"{docno}='{realno}'";
            }
            else
            {
                //标准
                path = $"{codefield}='{realno}'";
            }
            //添加组织参数
            object org = ReflexUtils.GetObjectValue("Org", dto);
            if ( org!= null && org is CopyOfCommonArchiveDataDTOData)
            {
                CopyOfCommonArchiveDataDTOData org1 = (CopyOfCommonArchiveDataDTOData)org;
                if (org1.ID > 0)
                {
                    path = path + $" and Org={org1.ID}";
                }else if (!string.IsNullOrEmpty(org1.Code))
                {
                    path = path + $" and Org.Code='{org1.Code}'";
                }
            }

            return path;
        }

        public static List<object> DTOListPropCopy(List<object> fromdtos,Type toType)
        {
            if(fromdtos == null)
                return null; 

            List<object> todtos = new List<object>();
            foreach(object fromdto in fromdtos)
            {
                object todto = Activator.CreateInstance(toType);
                DTOPropCopy(fromdto,todto);
                todtos.Add(todto);
            }
            return todtos;
        }

        /// <summary>
        /// DTO属性赋值,来源DTO->目标DTO
        /// </summary>
        /// <param name="fromdto">来源DTO</param>
        /// <param name="todto">目标DTO</param>
        /// <exception cref="Exception"></exception>
        public static void DTOPropCopy(object fromdto, object todto)
        {
            if (!IsValid) return;
            if (fromdto == null) return;
            if (todto == null) return;

            PropertyInfo[] propertyInfos = fromdto.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
            //循环每个原dto属性
            foreach (var prop in propertyInfos)
            {
                try
                {
                    //系统字段,获取/设置时会报错
                    if (prop.Name=="SysState"
                        ||prop.Name== "SysEntityType"
                        || prop.Name == "InnerData")
                        continue;

                    //判断原属性是否有值
                    if (prop.GetValue(fromdto) != null)
                    {
                        //目标属性
                        PropertyInfo toprop = todto.GetType().GetProperty(prop.Name);
                        //判断目标属性是否存在
                        if (toprop == null)
                        {
                            //不存在直接跳过
                            continue;
                        }
                        if (toprop.PropertyType.IsSubclassOf(typeof(DataTransObjectBase)))
                        {
                            //如果目标dto属性类型是dto类型,递归处理下层属性
                            object todto1 = Activator.CreateInstance(toprop.PropertyType);
                            DTOPropCopy(prop.GetValue(fromdto), todto1);
                            toprop.SetValue(todto, todto1);
                        }
                        else if (toprop.PropertyType.IsGenericType && toprop.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
                        {
                            //如果目标dto属性类型是list<dto>类型,循环递归
                            if (!(prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>)))
                                throw new Exception($"属性{prop.Name}必须是集合类型");

                            //获取list<>中的数据类型
                            Type fromType = prop.PropertyType.GetGenericArguments()[0];
                            Type fromlistType = prop.PropertyType;
                            Type toType = toprop.PropertyType.GetGenericArguments()[0];
                            Type tolistType = toprop.PropertyType;
                            //获取原属性list数据
                            IList flist = (IList)prop.GetValue(fromdto);
                            List<object> flist1 = new List<object>();
                            foreach (object item in flist)
                            {
                                flist1.Add(item);
                            }
                            //转换为目标属性list数据
                            List<object> tolist = DTOListPropCopy(flist1, toType);
                            IList tolist1 = (IList)Activator.CreateInstance(tolistType);
                            foreach (object item in tolist)
                            {
                                tolist1.Add(Convert.ChangeType(item, toType));
                            }
                            toprop.SetValue(todto, tolist1);
                        }
                        else if (toprop.PropertyType == typeof(DateTime))
                        {
                            //日期类型处理
                            if (prop.GetValue(fromdto) != null)
                            {
                                string val = prop.GetValue(fromdto).ToString();
                                if (string.IsNullOrEmpty(val)) continue;
                                DateTime date = DateTime.Parse(val);
                                toprop.SetValue(todto, date);
                            }
                        }
                        else
                        {
                            //其他类型处理
                            toprop.SetValue(todto, prop.GetValue(fromdto));
                        }
                    }
                }
                catch(Exception ex)
                {
                    throw new Exception($"属性名称:[{prop.Name}],值:[{prop.GetValue(fromdto)}]异常明细:[{ex.Message}]", ex);
                }
            }
        }
    }
}
